Part 9 - 暗号化されたデータを使ってのプログラミンング入門

信じるか信じないかはさておき、暗号化されたデータを使ってコンピューテーションすることも可能です。全ての変数暗号化されているような環境でもプログラムは実行できるんです。

このチュートリアルでは、暗号化されたデータを使ってのコンピューテーションの基本的なツールについて学習します。特にSecure Multi-Party Computationと呼ばれる人気のアプローチを紹介します。このレッスンでは、暗号化されたデータで実行できる暗号化された計算機をつくります。

Authors:

References:

Step 1: Secure Multi-Party Computationを使った暗号化

SMPCは一見するととても変わった暗号手法です。公開鍵、秘密鍵のペアでの暗号化を行うかわりに、データは複数のshares(数字)に分割されます。そして、それぞれが秘密鍵のように扱われます。一般的にはこれらのsharesは2人以上の所有者に分散されます。暗号化されたデータを複合化するためには全ての所有者が複合化を認める必要があります。別の言い方をすると、全ての所有者がそれぞれ秘密鍵を持っているということです。

Encrypt()

では、変数xを暗号化するにはどうすれば良いでしょう。以下の方法で可能です。

暗号化は浮動小数点数や実数を使いません。その代わりにinteger quotient ringと呼ばれる数学空間を使います。基本的には0 から Q-1までの整数です。Qは実験で扱う数字を扱うに足るだけの十分に大きな素数です。実際にはあ与えられた数xに対してx % Qを行う事で環を実現します。(そのため、x' > Qの状態は避ける必要があります)


In [ ]:
Q = 1234567891011

In [ ]:
x = 25

In [ ]:
import random

def encrypt(x):
    share_a = random.randint(-Q,Q)
    share_b = random.randint(-Q,Q)
    share_c = (x - share_a - share_b) % Q
    return (share_a, share_b,  share_c)

In [ ]:
encrypt(x)

見ての通り、変数xを3つの異なるsharesに分割してみました。この3つのsharesは3人の異なる所有者に送ることができます。

Decrypt()

もし、複合化したいときは、シンプルに3つのsharesの合計を取って、剰余演算を実行します。(mod Q)


In [ ]:
def decrypt(*shares):
    return sum(shares) % Q

In [ ]:
a,b,c = encrypt(25)

In [ ]:
decrypt(a, b, c)

重要な事は、3つの内、2つのsharesだけだと複合化は上手くいかないという事です。


In [ ]:
decrypt(a, b)

という事は、複合化には全ての所有者の参加が必要だということです。これは、sharesが秘密鍵のように機能することを意味します。

Step 2: SMPCを使っての基本的な演算処理

しかしながら、Secure Multi-Party Computationの真の能力は、暗号化された変数を暗号化されたまま演算処理が行える事にあります。 それでは、見てみましょう。


In [ ]:
x = encrypt(25)
y = encrypt(5)

In [ ]:
def add(x, y):
    z = list()
    # 一人目のワーカーが自分のshareを足し合わせます
    z.append((x[0] + y[0]) % Q)
    
    # 二人目のワーカーが自分のshareを足し合わせます
    z.append((x[1] + y[1]) % Q)
    
    # 三人目のワーカーが自分のshareを足し合わせます
    z.append((x[2] + y[2]) % Q)
    
    return z

In [ ]:
decrypt(*add(x,y))

成功です

ご覧の通り、暗号化された値は、shares事に別々に計算され、その後正しく複合化できています。 (25 + 5 == 30)

実際のところ、SMPCでは以下の演算が使えます。

  • 加算 (私たちが今見てきた通りです)
  • 乗算
  • 比較

これらの基本的な演算を応用することで、私たちはどんなコンピューテーションも実行できるんです。

次のセクションでは、PySyftのライブラリと合わせて使う方法をご紹介します。

Step 3: PySyftを使ってのSMPC

前のセクションではSMPCがどう動作するのかについての直感的な説明をしました。しかし、実際には、加算や乗算のような原始的なプリミティブを毎回毎回自分たちで書きたくはありません。そこでこのセクションでは、PySyftを使ってどのように暗号化されたデータどうしのコンピューテーションを行うのかについて紹介します。特に、加算、乗算、そして比較について取り上げます。

それでは複数のバーチャルワーカーを作成しましょう(もうそろそろ慣れてきましたか?)。


In [ ]:
import torch
import syft as sy
hook = sy.TorchHook(torch)

bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
bill = sy.VirtualWorker(hook, id="bill")

暗号化/複合化の基本

暗号化はPySyftの.share()を実行するだけです。複合化は.get()を実行するだけです。


In [ ]:
x = torch.tensor([25])

In [ ]:
x

In [ ]:
encrypted_x = x.share(bob, alice, bill)

In [ ]:
encrypted_x.get()

暗号化された変数の確認

Bob、Alice、Billを細かく見ると彼らのsharesが確認できます。


In [ ]:
bob._objects

In [ ]:
x = torch.tensor([25]).share(bob, alice, bill)

In [ ]:
# Bobのshare
bobs_share = list(bob._objects.values())[0]
bobs_share

In [ ]:
# Aliceのshare
alices_share = list(alice._objects.values())[0]
alices_share

In [ ]:
# Billのshare
bills_share = list(bill._objects.values())[0]
bills_share

その気になれば、理論通りに、変数を複合化することができます。


In [ ]:
Q = x.child.field

(bobs_share + alices_share + bills_share) % Q

見ての通りですが、ここで.share() と呼んでいるものは、一つの変数を三分割したもので、それぞれ別のワーカーへ送られています。

暗号化された数字を使っての数学計算

PyTorchのTensorも、暗号化して、暗号化したまま演算を実行することができます。


In [ ]:
x = torch.tensor([25]).share(bob,alice)
y = torch.tensor([5]).share(bob,alice)

In [ ]:
z = x + y
z.get()

In [ ]:
z = x - y
z.get()

暗号化された数値を使っての乗算

乗算の実行には乱数を生成してくれる第三者が必要です。ここでは"crypto provider"と呼びます。ここで注意しておかなければいけないのは、"Crypt provider"はsharesの所有者であってはならないという事です。


In [ ]:
crypto_provider = sy.VirtualWorker(hook, id="crypto_provider")

In [ ]:
x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)

In [ ]:
# 乗算

z = x * y
z.get()

行列を使った乗算にも使えます。


In [ ]:
x = torch.tensor([[1, 2],[3,4]]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([[2, 0],[0,2]]).share(bob,alice, crypto_provider=crypto_provider)

In [ ]:
# 行列演算

z = x.mm(y)
z.get()

暗号化されたデータと暗号化されたデータの比較

暗号化された値どうしの比較も可能です。SecureNNというプロトコルは必要になりますが、それだけです。結果ももちろん暗号化されています。SecureNNの詳細はこちらでご確認ください。


In [ ]:
x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)

In [ ]:
z = x > y
z.get()

In [ ]:
z = x <= y
z.get()

In [ ]:
z = x == y
z.get()

In [ ]:
z = x == y + 20
z.get()

最大値を取得する演算も実行できます。


In [ ]:
x = torch.tensor([2, 3, 4, 1]).share(bob,alice, crypto_provider=crypto_provider)
x.max().get()

In [ ]:
x = torch.tensor([[2, 3], [4, 1]]).share(bob,alice, crypto_provider=crypto_provider)
max_values, max_ids = x.max(dim=0)
max_values.get()

おめでとうございます!コミュニティに入ろう!

本チュートリアルを完了しました。おめでとうございます!もし、このチュートリアルを気に入って、プライバシーに配慮した非中央集権的なAI技術や付随する(データやモデルの)サプライチェーンにご興味があって、プロジェクトに参加したいと思われるなら、以下の方法で可能です。

PySyftのGitHubレポジトリにスターをつける

一番簡単に貢献できる方法はこのGitHubのレポジトリにスターを付けていただくことです。スターが増えると露出が増え、より多くのデベロッパーにこのクールな技術の事を知って貰えます。

Slackに入る

最新の開発状況のトラッキングする一番良い方法はSlackに入ることです。 下記フォームから入る事ができます。 http://slack.openmined.org

コードプロジェクトに参加する

コミュニティに貢献する一番良い方法はソースコードのコントリビューターになることです。PySyftのGitHubへアクセスしてIssueのページを開き、"Projects"で検索してみてください。参加し得るプロジェクトの状況を把握することができます。また、"good first issue"とマークされているIssueを探す事でミニプロジェクトを探すこともできます。

寄付

もし、ソースコードで貢献できるほどの時間は取れないけど、是非何かサポートしたいという場合は、寄付をしていただくことも可能です。寄附金の全ては、ハッカソンやミートアップの開催といった、コミュニティ運営経費として利用されます。

OpenMined's Open Collective Page


In [ ]: